package rtkacaster

import (
	"fmt"
	"gitee.com/ymofen/deadlock"
	"gitee.com/ymofen/golog"
	"gitee.com/ymofen/sputils"
	"kpl-plugs/sp/ntripcaster"
	"time"
)

type rtkaCaster struct {
	lk     deadlock.RWMutex
	ex     *sputils.Subchannel
	logger golog.Logger
	caster *ntripcaster.NtripCaster
}

type rtkaNtripClientSession struct {
	sid        string
	reqService string
}

var (
	caster            = &rtkaCaster{ex: sputils.NewSubchannel()}
	casterAddr string = "0.0.0.0:8003"
)

func (this *rtkaCaster) GetActived() bool {
	this.lk.RLock()
	defer this.lk.RUnlock()
	return this.caster != nil
}

func (this *rtkaCaster) GetAddr() string {
	this.lk.RLock()
	defer this.lk.RUnlock()
	if this.caster == nil {
		return ""
	}
	return this.caster.ListenAddr()
}

func (this *rtkaCaster) Open() error {
	this.lk.Lock()
	defer this.lk.Unlock()
	if this.caster != nil {
		return fmt.Errorf("rtkaCaster already open")
	}
	this.logger = golog.Default().WithOptionEx(golog.WithOptionPrefix("caster"))
	opt := &ntripcaster.ServerOptions{Addr: casterAddr}
	c := ntripcaster.NewNtripCaster(opt)
	err := c.Start()
	if err != nil {
		return err
	}
	c.OnNtripAccept = func(c *ntripcaster.Client, req *ntripcaster.NtripRequestHead, data []byte) {
		if c.GetKind() == ntripcaster.CLIENT_NTRIPCLIENT {

			mp := req.Mp
			if len(mp) == 0 {
				c.WriteAndReqDis([]byte(ntripcaster.ERR_BADMountPoint), ntripcaster.AuthError)
				return
			}

			sess := &rtkaNtripClientSession{sid: fmt.Sprintf("sid-%d", c.GetCID()), reqService: mp}
			this.ex.Sub(sess.sid, mp, func(id, topic string, args ...interface{}) (ok bool) {
				c.PostBuf(args[0].([]byte))
				return true
			})

			this.logger.Infof("%s clients connected %s", mp, c.RemoteAddr())

			c.Tag = sess
			c.PostBuf([]byte(ntripcaster.ICY_200_OK))
		}
	}
	c.OnNtripDataRecv = func(c *ntripcaster.Client, data []byte) {
		if c.GetKind() == ntripcaster.CLIENT_NTRIPCLIENT && c.Tag != nil {
			sess := c.Tag.(*rtkaNtripClientSession)
			this.logger.Debugf("%s clients recv %s", sess.sid, string(data))
		}
	}
	c.OnNtripClose = func(c *ntripcaster.Client) {
		if c.GetKind() == ntripcaster.CLIENT_NTRIPCLIENT && c.Tag != nil {
			sess := c.Tag.(*rtkaNtripClientSession)
			this.ex.Unsub(sess.sid, sess.reqService)
		}
	}
	this.caster = c

	return nil
}

func CheckStartRtkACaster() {
	if caster.GetActived() {
		return
	}
	caster.Open()
	time.Sleep(time.Millisecond * 100)
}

func GetRtkACasterAddr() string {
	return caster.GetAddr()
}

func RtkACasterPub(mp string, buf []byte) error {
	r := caster.ex.Pub(mp, 0, buf)
	if r == -1 {
		return fmt.Errorf("rtkacaster pub fail")
	}
	return nil
}
